GitHub上のAnsiblePlaybookをSystems Managerで実行する
はじめに
中山(順)です
以前、弊社の大栗より、「EC2の管理を行えるSystems ManagerでgithubやS3に配置したファイルをローカルにダウンロードして実行することが可能になりました。」という内容をご紹介しました。
今回、これを応用してGitHub上のAnsiblePlaybookをEC2インスタンス上で実行させてみました。
おさらい
"AWS-RunRemoteScript"でやっていることは、以下の2つです。
- コンテンツ(スクリプトなど)のダウンロード
- https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-downloadContent
- コマンドの実行
- (Windows) https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-runPowerShellScript
- (Linux) https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html#aws-runShellScript
やってみた
これを使用して、以下の処理を実行します。
- Ansible Playbook一式のダウンロード
- Ansible Playbookのローカル実行
手順は以下の公式ドキュメントにもあるので、適宜参照してください。
Run Ansible Playbooks from GitHub
事前準備
Systems Managerを利用するための準備作業および動作要件は、公式ドキュメントもしくは弊社ブログをご確認ください。
Setting Up AWS Systems Manager
EC2 Systems Manager – 特集カテゴリー –
前提条件
今回の検証は以下の前提のもとで実施します。
- 以下のようなのEC2インスタンスを用意
- Ansibleをインストール
- Public Subnetに配置
- Linuxインスタンス (Amazon Linux AMI 2017.09.1 (HVM), SSD Volume Type - ami-19910c7f) を利用
- Run Commandを実行できる必要最低限の権限をインスタンスに付与(インスタンスプロファイル)
Ansibleは以下のコマンドでインストールしました。
sudo pip install ansible
Playbookの作成
今回は、以下のタスクを実行するだけの簡単なPlaybookを作成します。
- yum update
- httpdのインストールおよび起動
その際、それぞれを別のロールで定義します。
Playbookは以下の手順で作成しました。
- GitHubにリポジトリーを作成
- 作業環境にリポジトリーをクローン
- ディレクトリの作成
- Playbookの作成
- GitHubにリポジトリーをプッシュ
GitHubにリポジトリーを作成
GitHubにリポジトリを作成します。
以降の手順で作成されるPlaybookはこちらにありますので、ご参考までに。
nakayamanobuhiro/example-ansible-playbook-ssm
作業環境にリポジトリーをクローン
作業用ディレクトリを作成します。
mkdir ~/tmp_devio cd ~/tmp_devio
リポジトリーをクローンします
git clone https://github.com/nakayamanobuhiro/example-ansible-playbook-ssm.git cd ./example-ansible-playbook-ssm
ディレクトリの作成
ロールを配置するディレクトリを作成します。 今回はansible-galaxyコマンドを利用してディレクトリと(空の)ファイルを作成します。(地味に便利)
mkdir ./roles ansible-galaxy init --init-path=roles common ansible-galaxy init --init-path=roles web ls -R
.: README.md roles ./roles: common web ./roles/common: README.md defaults files handlers meta tasks templates tests vars ./roles/common/defaults: main.yml ./roles/common/files: ./roles/common/handlers: main.yml ./roles/common/meta: main.yml ./roles/common/tasks: main.yml ./roles/common/templates: ./roles/common/tests: inventory test.yml ./roles/common/vars: main.yml ./roles/web: README.md defaults files handlers meta tasks templates tests vars ./roles/web/defaults: main.yml ./roles/web/files: ./roles/web/handlers: main.yml ./roles/web/meta: main.yml ./roles/web/tasks: main.yml ./roles/web/templates: ./roles/web/tests: inventory test.yml ./roles/web/vars: main.yml
Playbookの作成
ansible-playbookコマンドを実行する際に指定するPlaybookのファイル名を指定します。
FILE_NAME_TOP="playbook.yml"
Playbookを生成します。
リモートホストで実行することも想定し、hosts: all
とします。
(Playbookを実行する際に、ansible-playbook -i "localhost," -c local playbook.yml
のように実行します。)
cat << EOF > ${FILE_NAME_TOP} --- - name: httpd hosts: all remote_user: ec2-user become: yes roles: - common - web EOF
yum updateを実行するためのPlaybookを作成します。
FILE_NAME_COMMON="./roles/common/tasks/main.yml" cat << EOF > ${FILE_NAME_COMMON} --- - name: upgrade all packages yum: name: '*' state: latest EOF
httpdをインストールするためのPlaybookを作成します。
FILE_NAME_WEB="./roles/web/tasks/main.yml" cat << EOF > ${FILE_NAME_WEB} --- - name: install the latest version of httpd yum: name=httpd state=latest - name: httpd service state service: name=httpd state=started enabled=yes EOF
GitHubにリポジトリーをプッシュ
リポジトリーにPlaybookをプッシュします。
git add . git commit -m "First commit" git push origin master
Playbookの実行
パラメーターの準備
"AWS-RunRemoteScript"ドキュメントを実行するにあたり、以下のパラメーターを決定する必要があります。
- 実行対象のインスタンスIDもしくはタグ
- 今回はインスタンスIDで対象を指定します
- owner
- リポジトリーのオーナー名
- repository
- リポジトリー名
- path
- ダウンロードしたいファイルもしくはディレクトリのパス
- 今回はリポジトリー上のファイルをすべて取得します
- getOptions
- ブランチ名もしくはコミットID
- 指定は任意(デフォルトはbranch:master,commitID:head)
プライベートリポジトリーを利用する場合は、これらに加えてtokenInfoにGitHubのアクセストークンを指定する必要があります。 パラメーターストアにKMSで暗号化して保存し、それを参照することも可能です。
INSTANCE_ID="i-0xxxxxxxxxxxxxxxx" OWNER="nakayamanobuhiro" REPOSITORY="example-ansible-playbook-ssm" DOWNLOAD_PATH="/" GET_OPTIONS="branch:master" PARAMETERS="{\"sourceType\":[\"GitHub\"],\"sourceInfo\":[\"{\\\"owner\\\":\\\"${OWNER}\\\", \\\"repository\\\": \\\"${REPOSITORY}\\\", \\\"path\\\": \\\"${DOWNLOAD_PATH}\\\", \\\"getOptions\\\": \\\"${GET_OPTIONS}\\\"}\"],\"commandLine\":[\"ansible-playbook -i \\\"localhost,\\\" -c local playbook.yml\"]}" && echo ${PARAMETERS}
{"sourceType":["GitHub"],"sourceInfo":["{\"owner\":\"nakayamanobuhiro\", \"repository\": \"example-ansible-playbook-ssm\", \"path\": \"/\", \"getOptions\": \"branch:master\"}"],"commandLine":["ansible-playbook -i \"localhost,\" -c local playbook.yml"]}
Playbookの実行
Playbook(GitHubリポジトリー)とRunCommand実行時に必要なパラメーターが準備できました。 Ansibe Playbookを実行してみます。
aws ssm send-command \ --document-name "AWS-RunRemoteScript" \ --instance-ids ${INSTANCE_ID} \ --parameters "${PARAMETERS}"
{ "Command": { "Comment": "", "Status": "Pending", "MaxErrors": "0", "Parameters": { "commandLine": [ "ansible-playbook -i \"localhost,\" -c local playbook.yml" ], "sourceInfo": [ "{\"owner\":\"nakayamanobuhiro\", \"repository\": \"example-ansible-playbook-ssm\", \"path\": \"/\", \"getOptions\": \"branch:master\"}" ], "sourceType": [ "GitHub" ] }, "ExpiresAfter": 1515183224.362, "ServiceRole": "", "DocumentName": "AWS-RunRemoteScript", "TargetCount": 1, "OutputS3BucketName": "", "NotificationConfig": { "NotificationArn": "", "NotificationEvents": [], "NotificationType": "" }, "CompletedCount": 0, "Targets": [], "StatusDetails": "Pending", "ErrorCount": 0, "OutputS3KeyPrefix": "", "RequestedDateTime": 1515176024.362, "CommandId": "4da78de8-5287-408d-8bd3-d7ab1a5411c4", "InstanceIds": [ "i-097a8923a6beb618a" ], "MaxConcurrency": "50" } }
動作確認
RunCommandの実行結果を確認します。 "AWS-RunRemoteScript"ドキュメントでは複数のプラグインが実行されるため、まずはlist-command-invocationsでRunCommandのステータスを確認します。 以下のように、成功していることを確認できました。
aws ssm list-command-invocations \ --command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \ --instance-id ${INSTANCE_ID}
{ "CommandInvocations": [ { "Comment": "", "Status": "Success", "CommandPlugins": [], "ServiceRole": "", "InstanceId": "i-097a8923a6beb618a", "DocumentName": "AWS-RunRemoteScript", "NotificationConfig": { "NotificationArn": "", "NotificationEvents": [], "NotificationType": "" }, "StatusDetails": "Success", "StandardOutputUrl": "", "StandardErrorUrl": "", "InstanceName": "", "CommandId": "4da78de8-5287-408d-8bd3-d7ab1a5411c4", "RequestedDateTime": 1515176024.547 } ] }
RunCommandの実行ログを確認します。 まずは"AWS-RunRemoteScript"ドキュメントに含まれるプラグイン名を確認します。
aws ssm get-document \ --name AWS-RunRemoteScript \ --query "Content" \ --output text \ | jq -r .mainSteps[].name
downloadContent runPowerShellScript runShellScript
"runPowerShellScript"はLinux上ではスキップされるようにドキュメントが定義されているので、"downloadContent"および"runShellScript"のログを確認します。
まずは、"downloadContent"を確認します。
aws ssm get-command-invocation \ --command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \ --instance-id ${INSTANCE_ID} \ --plugin-name downloadContent \ --query "StandardOutputContent" \ --output text
Content downloaded to /var/lib/amazon/ssm/i-097a8923a6beb618a/document/orchestration/4da78de8-5287-408d-8bd3-d7ab1a5411c4/downloads/
次に、"runShellScript"を確認します。
aws ssm get-command-invocation \ --command-id 4da78de8-5287-408d-8bd3-d7ab1a5411c4 \ --instance-id ${INSTANCE_ID} \ --plugin-name runShellScript \ --query "StandardOutputContent" \ --output text
PLAY [nginx] ******************************************************************* TASK [Gathering Facts] ********************************************************* ok: [localhost] TASK [common : upgrade all packages] ******************************************* ok: [localhost] TASK [web : install the latest version of httpd] ******************************* changed: [localhost] TASK [web : httpd service state] *********************************************** changed: [localhost] PLAY RECAP ********************************************************************* localhost : ok=4 changed=2 unreachable=0 failed=0
意図したとおり機能しているかを確認します。 今回はhttpdをインストールしただけなので、デフォルトのコンテンツが表示されるか確認します。 以下の通り、httpdからTest Pageが取得できることが確認できました。
curl xx.xx.xx.xx | head
``` % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 3839 100 3839 0 0 159k 0 --:--:-- --:--:-- --:--:-- 163k